#pragma once
#include "../Ode.h"

namespace Skill
{
	namespace Ode
	{
		ref class DVector3;
		ref class DVector4;
		ref class DMatrix3;

		public ref class DQuaternion : DIUnmanagedPointer
		{
			INTERNAL_CLASS_DECLARATION(DQuaternion,dReal);
		public:
			UNMANAGEDPOINTER_DECLARATION();

			DQuaternion()
			{
				_SetPointer(new dQuaternion(),true);
			}
			DQuaternion(dReal x,dReal y,dReal z,dReal w)
			{
				_SetPointer(new dQuaternion(),true);
				_This[0] = x;
				_This[0] = y;
				_This[0] = z;
				_This[0] = w;
			}

			VALUE_PROP_DECLARATION_GETSET(dReal,X);
			VALUE_PROP_DECLARATION_GETSET(dReal,Y);
			VALUE_PROP_DECLARATION_GETSET(dReal,Z);
			VALUE_PROP_DECLARATION_GETSET(dReal,W);

			static VALUE_PROP_DECLARATION_GET(DQuaternion^,Identity);
			void SetIdentity();

			void SetFromAxisAndAngle(dReal ax, dReal ay, dReal az, dReal angle);
			void SetFromAxisAndAngle(DVector3^ a, dReal angle);
			void SetFromAxisAndAngle(DVector4^ a, dReal angle);

			static DQuaternion^ FromAxisAndAngle(dReal ax, dReal ay, dReal az, dReal angle);
			static DQuaternion^ FromAxisAndAngle(DVector3^ a, dReal angle);
			static DQuaternion^ FromAxisAndAngle(DVector4^ a, dReal angle);


			/* Quaternion multiplication, analogous to the matrix multiplication routines. */

			/// <summary>
			/// rotate by qc, then qb
			/// </summary>
			void Multiply0(DQuaternion^ qb, DQuaternion^ qc);
			/// <summary>
			/// rotate by qc, then by inverse of qb
			/// </summary>
			void Multiply1(DQuaternion^ qb, DQuaternion^ qc);
			/// <summary>
			/// rotate by inverse of qc, then by qb
			/// </summary>
			void Multiply2(DQuaternion^ qb, DQuaternion^ qc);
			/// <summary>
			/// rotate by inverse of qc, then by inverse of qb
			/// </summary>
			void Multiply3(DQuaternion^ qb, DQuaternion^ qc);

			void SetFromRotation(DMatrix3^ r);
			static DQuaternion^ FromRotation(DMatrix3^ r);

			void SetDQfromW(DVector3^ w, DQuaternion^ q);
			static DQuaternion^ DQfromW(DVector3^ w, DQuaternion^ q);

			virtual String^ ToString() override
			{
				return String::Format("X: {0} Y: {1} Z: {2} W: {3}",_This[0],_This[1],_This[2],_This[3]);
			}
		};
	}
}